package com.xgpro.common.utils;

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddressList;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 2016/3/9
 * 写出Excel工具类
 */
public class WriteExcelUtil {
    /**
     * 写出带有选择框限制的excel
     * @param response HttpServletResponse
     * @param fileName 写出文件的文件名,若没有添加文件类型后缀，则默认添加".xls"
     * @param headers  标题行内容
     * @param data  数据行内容（需要和标题行顺序一样，只支持各种普通类型）
     * @param maps  需要做选择框限制的列的集合  说明：1.map中key为"titleContent"中需存入，需要做选择框的列顶部标题内容  2.map中key为"data"中需存入，所能选择的数据集合
     * @throws Exception
     */
    public static void writeExcelHaveSelectBox(HttpServletResponse response, String fileName, String[] headers, List<List<Object>> data, List<Map<String, Object>> maps) throws Exception {
        if(maps == null || maps.isEmpty()){
            throw new RuntimeException("参数maps为空");
        }
        // 基础操作
        HSSFWorkbook workbook = baseHandle(headers, data);
        // 文件名操作
        fileNameHandle(response, fileName);
        // 如果maps里有数据，则生成选择框限制
        writeSelectionBox(headers, maps, workbook);
        // 写出文件
        workbook.write(response.getOutputStream());
    }
    /**
     * 写出普通的excel
     *
     * @param response HttpServletResponse
     * @param fileName 写出文件的文件名,若没有添加文件类型后缀，则默认添加".xls"
     * @param headers  标题行内容
     * @param data     数据行内容（需要和标题行顺序一样，只支持各种普通类型）
     */
    public static void writeExcel(HttpServletResponse response, String fileName, String[] headers, List<List<Object>> data) throws IOException {
        // 基础操作
        HSSFWorkbook workbook = baseHandle(headers, data);
        // 文件名操作
        fileNameHandle(response, fileName);
        // 写出excel
        workbook.write(response.getOutputStream());
    }
    /**
     * 写出excel的一些基础操作
     * @param headers      标题行内容
     * @param data         数据行内容
     * @return 返回操作的HSSFWorkbook
     * @throws Exception
     */
    private static HSSFWorkbook baseHandle(String[] headers, List<List<Object>> data) throws IOException {
        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet();
        // 设置表格默认列宽度为20个字节
        sheet.setDefaultColumnWidth(20);
        // 写入标题行
        writeTitleRow(headers, workbook);
        // 如果data有数据，则遍历集合数据，产生数据行
        if(data != null && !data.isEmpty()){
            writeDataRow(data, workbook);
        }
        // 返回操作的HSSFWorkbook
        return workbook;
    }

    /**
     * 文件名操作
     * @param response HttpServletResponse
     * @param fileName 写出文件的文件名,若没有添加文件类型后缀，则默认添加".xls"
     */
    private static void fileNameHandle(HttpServletResponse response, String fileName) throws IOException{
        // 如果fileName没有"."，说明没有加文件类型后缀，则默认添加".xls"
        if (fileName.indexOf(".") == -1) {
            fileName += ".xls";
        }
        // 文件名转码
        fileName = new String(fileName.getBytes(), "ISO-8859-1");
        // 在请求头中写入文件名
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
    }
    /**
     * 生成选择框限制
     * @param headers 标题行内容（用于确定，有选择框限制的列位置）
     * @param maps  需要做选择框限制的列的集合  说明：1.map中key为"titleContent"中需存入，需要做选择框的列顶部标题内容  2.map中key为"data"中需存入，所能选择的数据集合
     */
    private static void writeSelectionBox(String[] headers, List<Map<String, Object>> maps, HSSFWorkbook workbook) throws Exception{
        for(Map<String, Object> map : maps){
            // 需要做选择框限制的列的标题内容
            String titleContent = map.get("titleContent").toString();
            // 能选择的数据
            List<Object> list = (List<Object>) map.get("data");
            // 所能的数据不能超过50条（经过测试得出，超过50则会报错）
            if(list.size() > 50){
                throw new RuntimeException("所能选择的选项不能超过50");
            }
            // 确定有选择框限制的列位置
            Integer index = null;
            for(int i = 0; i < headers.length; ++i){
                if(headers[i].equals(titleContent)){
                    index = i;
                    break;
                }
            }
            // 如果确定不了位置，则弹出一个错误
            if(index == null){
                throw new RuntimeException("寻找不到指定列");
            }
            // 产生下拉框
            DVConstraint constraint1 = DVConstraint.createExplicitListConstraint(list.toArray(new String[list.size()]));
            // 设置数据有效性加载在哪个单元格上,四个参数分别是：起始行、终止行、起始列、终止列
            CellRangeAddressList regions1 = new CellRangeAddressList(1, 500, 1, 1);
            // 数据有效性对象
            HSSFDataValidation data_validation_list1 = new HSSFDataValidation(regions1, constraint1);
            workbook.getSheetAt(0).addValidationData(data_validation_list1);
        }
    }

    /**
     * 写入标题行
     * @param headers 标题行内容
     * @param workbook HSSFWorkbook
     */
    private static void writeTitleRow(String[] headers, HSSFWorkbook workbook){
        // 获取表格
        HSSFSheet sheet = workbook.getSheetAt(0);
        // 生成标题样式
        HSSFCellStyle titleStyle = workbook.createCellStyle();
        // 设置这些样式
        titleStyle.setAlignment(HorizontalAlignment.CENTER);//横向居中
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);//纵向居中

        // 生成标题字体
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 11);
        font.setFontName("黑体");
        // 把标题字体应用到标题样式
        titleStyle.setFont(font);
        //产生表格标题行
        HSSFRow row = sheet.createRow(0);
        for (int i = 0; i < headers.length; i++) {
            HSSFCell cell = row.createCell(i);
            cell.setCellStyle(titleStyle);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            cell.setCellValue(text);
        }
    }

    /**
     * 写入数据行
     * @param data 数据
     * @param workbook HSSFWorkbook
     */
    private static void writeDataRow(List<List<Object>> data, HSSFWorkbook workbook){
        // 获取表格
        HSSFSheet sheet = workbook.getSheetAt(0);
        // 生成并设置内容样式
        HSSFCellStyle contentStyle = workbook.createCellStyle();
        contentStyle.setAlignment(HorizontalAlignment.CENTER);//横向居中
        contentStyle.setVerticalAlignment(VerticalAlignment.CENTER);//纵向居中

        // 生成内容字体
        HSSFFont font2 = workbook.createFont();
        font2.setFontHeightInPoints((short) 11);
        font2.setFontName("宋体");
        // 把字体应用到当前的样式
        contentStyle.setFont(font2);
        int index = 0;
        for (List<Object> list : data) {
            index++;
            HSSFRow row = sheet.createRow(index);
            for (int i = 0; i < list.size(); i++) {
                HSSFCell cell = row.createCell(i);
                cell.setCellStyle(contentStyle);
                Object value = list.get(i);
                String textValue = null;
                if (value instanceof Boolean) {
                    boolean bValue = (Boolean) value;
                    textValue = "是";
                    if (!bValue) {
                        textValue = "否";
                    }
                } else if (value instanceof Date) {
                    Date date = (Date) value;
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    textValue = sdf.format(date);
                } else {
                    //其它数据类型都当作字符串简单处理
                    if (value != null) {
                        textValue = value.toString();
                    } else {
                        textValue = " ";
                    }
                }
                //如果不是图片数据，就利用正则表达式判断textValue是否全部由数字组成
                if (textValue != null) {
                    HSSFRichTextString richString = new HSSFRichTextString(textValue);
                    HSSFFont font3 = workbook.createFont();
                    richString.applyFont(font3);
                    cell.setCellValue(richString);
                }
            }
        }
    }
}